package com.test.platform.module.perf.service;

import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.test.common.component.RedisComponent;
import com.test.common.entity.perf.PerfResourceEntity;
import com.test.common.repository.perf.PerfResourceRepository;
import com.test.common.response.BizException;
import com.test.common.utils.SystemUtils;
import com.test.platform.module.perf.Config;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsCriteria;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

@Data
@Slf4j
@Service
public class PerfResourceService {

    @Resource(name = "perf_config")
    private Config config;

    @Resource
    private GridFsTemplate gridFsTemplate;

    @Resource
    private GridFSBucket gridFSBucket;

    @PostConstruct
    public void init() {
        log.info("INIT PerfResourceService");
    }

    @Resource
    private RedisComponent redisComponent;

    @Resource
    private PerfResourceRepository perfResourceRepository;

    @SneakyThrows
    public HashMap<String, ArrayList<String>> fileUpload(List<FileItem> fileItems) {

        HashMap<String, ArrayList<String>> data = new HashMap<>();
        data.put("OK", new ArrayList<>());
        data.put("KO", new ArrayList<>());

        for (FileItem fileItem : fileItems) {

            if (fileItem.isFormField()) {
                log.warn("这里不需要传非文件内容|{}|{}", fileItem.getFieldName(), fileItem.getString("utf-8"));
            } else {
                String fileName = fileItem.getName().substring(fileItem.getName().lastIndexOf("\\") + 1);

                if (!StringUtils.endsWith(fileName, ".csv")) {
                    data.get("KO").add(fileName);
                    log.info("仅支持上传csv文件|{}", fileItem);
                    continue;
                }
                log.info("上传文件|{}", fileName);

                // 先保存文件
                String objectId = gridFsTemplate.store(fileItem.getInputStream(), fileName).toHexString();

                // 先更新数据库
                Optional<PerfResourceEntity> optional = perfResourceRepository.findByName(fileName);
                if (optional.isPresent()) {

                    log.info("数据已存在，修改老数据");
                    PerfResourceEntity perfResourceEntity = optional.get();

                    // 数据入库
                    perfResourceEntity = new PerfResourceEntity(perfResourceEntity.getId(), fileName, SystemUtils.getUser().getName(),
                            objectId, fileItem.getSize() / 1024);

                    perfResourceRepository.save(perfResourceEntity);
                } else {

                    log.info("数据不存在，添加新数据");

                    // 数据入库
                    PerfResourceEntity perfResourceEntity = new PerfResourceEntity(fileName, SystemUtils.getUser().getName(), objectId, fileItem.getSize() / 1024);
                    perfResourceRepository.save(perfResourceEntity);
                }

                data.get("OK").add(fileName);
            }
        }

        return data;
    }

    public void download(int id, HttpServletResponse response) {

        Optional<PerfResourceEntity> optional = perfResourceRepository.findById(id);

        try {
            if (optional.isPresent()) {
                PerfResourceEntity perfResourceEntity = optional.get();
                GridFSFile fsFile = gridFsTemplate.findOne(Query.query(GridFsCriteria.where("_id").is(perfResourceEntity.getObjectId())));
                if (fsFile != null) {
                    GridFsResource fsResource = new GridFsResource(fsFile, gridFSBucket.openDownloadStream(fsFile.getObjectId()));
                    log.info("文件大小|{}", fsResource.contentLength());

                    InputStream inputStream = fsResource.getInputStream();
                    ServletOutputStream outputStream = response.getOutputStream();
                    response.setContentType("application/octet-stream");
                    response.setHeader("Content-disposition", "attachment;filename=" + fsResource.getFilename());
                    response.setContentLengthLong(fsResource.contentLength());
                    int len;
                    byte[] buffer = new byte[1024 * 1024 * 100];
                    while ((len = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, len);
                        outputStream.flush();
                    }

                    response.flushBuffer();
                    outputStream.close();
                    inputStream.close();
                } else {
                    throw new BizException("资源文件丢失：" + perfResourceEntity.getObjectId());
                }
            } else {
                throw new BizException("未找到资源文件：" + id);
            }
        } catch (Exception e) {
            log.error("获取文件信息异常|{}", e.getMessage());
            e.printStackTrace();
            throw new BizException("获取文件信息异常", e);
        }
    }

    public String delete(int id) {

        try {
            Optional<PerfResourceEntity> optional = perfResourceRepository.findById(id);

            if (optional.isPresent()) {
                PerfResourceEntity perfResourceEntity = optional.get();
                gridFsTemplate.delete(Query.query(Criteria.where("_id").is(perfResourceEntity.getObjectId())));
                perfResourceRepository.delete(perfResourceEntity);
                return "删除成功";
            } else {
                throw new BizException("未找到资源文件：" + id);
            }
        } catch (Exception e) {
            log.error("资源文件删除失败：" + id);
            e.printStackTrace();
            throw new BizException("资源文件删除失败，可能还存在关联内容");
        }
    }

    // 页码前端从1开始计算，后端从0开始计算
    public Page<PerfResourceEntity> findAll(int page, int size) {
        page = page - 1;
        return perfResourceRepository.findAll(PageRequest.of(page, size, Sort.by("id").descending()));
    }

    public Object getAllNames() {
        return perfResourceRepository.getAllNames();
    }

    public Object getDetail(int id) {

        Optional<PerfResourceEntity> optionalPerfResourceEntity = perfResourceRepository.findById(id);

        try {
            if (optionalPerfResourceEntity.isPresent()) {
                PerfResourceEntity perfResourceEntity = optionalPerfResourceEntity.get();
                GridFSFile fsFile = gridFsTemplate.findOne(Query.query(GridFsCriteria.where("_id").is(perfResourceEntity.getObjectId())));
                if (fsFile != null) {

                    GridFsResource fsResource = new GridFsResource(fsFile, gridFSBucket.openDownloadStream(fsFile.getObjectId()));

                    // 最多读5M的文件
                    byte[] bs = new byte[1024 * 1024 * 5];
                    InputStream inputStream = fsResource.getInputStream();
                    int read = inputStream.read(bs);
                    inputStream.close();

                    if (read == -1) {
                        return new String(bs);
                    } else {
                        return new String(bs, 0, read);
                    }
                } else {
                    throw new BizException("脚本文件丢失：" + perfResourceEntity.getObjectId());
                }
            } else {
                throw new BizException("找不到文件，" + id);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException(e.getMessage());
        }
    }
}
